package com.authine.cloudpivot.ext.utils;

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AssignableTypeFilter;

import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class ClassUtils {

    private ClassUtils() {
    }

    /**
     * 获取指定包下某个类的所有非抽象子类
     *
     * @param parentClass 父类
     * @param packagePath 包路径
     * @param <T>         泛型
     * @return 类列表
     * @throws ClassNotFoundException 异常
     */
    public static <T> List<Class<T>> getSubClasses(final Class<T> parentClass, final String packagePath) throws ClassNotFoundException {

        ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
        provider.addIncludeFilter(new AssignableTypeFilter(parentClass));
        Set<BeanDefinition> components = provider.findCandidateComponents(packagePath);
        List<Class<T>> subClasses = new ArrayList<>();

        if (!components.isEmpty()) {
            for (BeanDefinition component : components) {
                @SuppressWarnings("unchecked")
                Class<T> cls = (Class<T>) Class.forName(component.getBeanClassName());
                if (Modifier.isAbstract(cls.getModifiers())) continue;
                subClasses.add(cls);
            }
        }

        return subClasses;
    }

    public static String[] getNullPropertyNames (Object source) {
        final BeanWrapper src = new BeanWrapperImpl(source);
        java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();

        Set<String> emptyNames = new HashSet<String>();
        for(java.beans.PropertyDescriptor pd : pds) {
            Object srcValue = src.getPropertyValue(pd.getName());
            if (srcValue == null) emptyNames.add(pd.getName());
        }
        String[] result = new String[emptyNames.size()];
        return emptyNames.toArray(result);
    }
}
